package com.sh.data.engine.domain.normalization.index.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.EnumUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.common.collect.Lists;
import com.sh.data.engine.common.enumDefinition.DSType;
import com.sh.data.engine.common.enumDefinition.IndexTimeGranularityEnum;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.domain.api.service.DataApiService;
import com.sh.data.engine.domain.base.model.BaseDomain;
import com.sh.data.engine.domain.base.model.PageResult;
import com.sh.data.engine.domain.base.model.UserContext;
import com.sh.data.engine.domain.dataasset.model.domain.TableInfoBizDomain;
import com.sh.data.engine.domain.dataasset.model.param.QueryTableParam;
import com.sh.data.engine.domain.dataasset.service.TableService;
import com.sh.data.engine.domain.dataasset.service.TblPropService;
import com.sh.data.engine.domain.integration.datasource.model.domain.DataSourceDomain;
import com.sh.data.engine.domain.integration.datasource.service.DataSourceService;
import com.sh.data.engine.domain.integration.documentCapture.model.domain.DocumentCaptureDomain;
import com.sh.data.engine.domain.integration.documentCapture.service.DocumentCaptureService;
import com.sh.data.engine.domain.integration.offline.model.domain.OfflineSyncDomain;
import com.sh.data.engine.domain.integration.offline.service.OfflineSyncService;
import com.sh.data.engine.domain.normalization.index.model.domain.*;
import com.sh.data.engine.domain.normalization.index.model.domain.IndexDomain.IndexCorrelation;
import com.sh.data.engine.domain.normalization.index.model.param.IndexDevParam;
import com.sh.data.engine.domain.normalization.index.model.param.IndexListParam;
import com.sh.data.engine.domain.normalization.index.model.param.IndexParam;
import com.sh.data.engine.domain.normalization.index.model.param.PreviewDataParam;
import com.sh.data.engine.domain.normalization.index.service.IndexCatalogService;
import com.sh.data.engine.domain.normalization.index.service.IndexMgtService;
import com.sh.data.engine.domain.normalization.index.service.IndexService;
import com.sh.data.engine.domain.normalization.modeldesign.model.model.domain.ModelDomain;
import com.sh.data.engine.domain.normalization.modeldesign.model.service.ModelService;
import com.sh.data.engine.domain.normalization.research.dataowner.model.domain.DataOwnerDomain;
import com.sh.data.engine.domain.normalization.research.themedesign.model.domain.ThemeDomain;
import com.sh.data.engine.domain.normalization.research.themedesign.service.ThemeService;
import com.sh.data.engine.domain.util.ConvertUtil;
import com.sh.data.engine.domain.workspace.index.model.domain.ProjectDomain;
import com.sh.data.engine.domain.workspace.index.service.ProjectService;
import com.sh.data.engine.domain.workspace.manager.service.StorageService;
import com.sh.data.engine.domain.workspace.manager.service.UserService;
import com.sh.data.engine.repository.dao.api.entity.DataApiEntity;
import com.sh.data.engine.repository.dao.dataasset.entity.TblPropEntity;
import com.sh.data.engine.repository.dao.integration.datasource.entity.DataSourceEntity;
import com.sh.data.engine.repository.dao.normalization.index.entity.IndexCatalog;
import com.sh.data.engine.repository.dao.normalization.index.entity.IndexEntity;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tinglan.ys
 * @description:
 * @date 2022/4/18 下午3:58
 */
@Service
@Slf4j
public class IndexMgtServiceImpl implements IndexMgtService {

    @Autowired
    private IndexCatalogService indexCatalogService;

    @Autowired
    private IndexService indexService;

//    @Autowired
//    private DataOwnerService dataOwnerService;

    @Autowired
    private TableService tableService;

//    @Autowired
//    private TableProductService tableProductService;

    @Autowired
    private DocumentCaptureService documentCaptureService;

    @Autowired
    private OfflineSyncService offlineSyncService;

    @Autowired
    private TblPropService tblPropService;

//    @Autowired
//    private CustomFormService customFormService;

    @Autowired
    private DataSourceService dataSourceService;

    @Lazy
    @Autowired
    private DataApiService dataApiService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProjectService projectService;

    @Autowired
    private ModelService modelService;

//    @Autowired
//    private OfflineDevMenuNodeService offlineDevMenuNodeService;

//    @Autowired
//    private CdmIndexTaskFlowService cdmIndexTaskFlowService;

    @Autowired
    private ThemeService themeService;

    @Autowired
    private UserService userService;

    @Autowired
    private StorageService storageService;

    @Override
    public List<IndexCatalogDomain> listCatalog(Long projectId) {

        List<IndexCatalog> indexCatalogList =
            indexCatalogService.list(
                new LambdaQueryWrapper<IndexCatalog>().eq(IndexCatalog::getProjectId, projectId));

        List<IndexCatalogDomain> indexCatalogDomains =
            ConvertUtil.copyProperties(indexCatalogList, IndexCatalogDomain.class);

        final ArrayList<IndexCatalogDomain> list = Lists.newArrayList(indexCatalogDomains);

        IndexCatalogDomain indexCatalogDomain = new IndexCatalogDomain();
        indexCatalogDomain.setProjectId(projectId);
        indexCatalogDomain.setId(0L);
        indexCatalogDomain.setPid(-1L);
        indexCatalogDomain.setLevel(0);
        indexCatalogDomain.setName("全部分组");

        list.add(indexCatalogDomain);

        return list;
    }

    @Override
    public List<IndexCatalogDomain> listCatalogWithTree(Long projectId) {
        // 1 查询所有分类
        List<IndexCatalog> indexCatalogList =
            indexCatalogService.list(
                new LambdaQueryWrapper<IndexCatalog>().eq(IndexCatalog::getProjectId, projectId));

        List<IndexCatalogDomain> indexCatalogDomains =
            ConvertUtil.copyProperties(indexCatalogList, IndexCatalogDomain.class);
        // 2 组装成父子的树形结构

        // 2.1 找到所有的1级分类
        List<IndexCatalogDomain> collect =
            indexCatalogDomains.stream()
                .filter(indexCatalog -> 0L == indexCatalog.getPid())
                .map(
                    (indexCatalogDomain) -> {
                        indexCatalogDomain.setChildren(
                            getChildrens(indexCatalogDomain, indexCatalogDomains));
                        return indexCatalogDomain;
                    })
                .sorted(
                    (indexCatalogDomain1, indexCatalogDomain2) -> {
                        return (indexCatalogDomain1.getSort() == null ? 0 : indexCatalogDomain1.getSort())
                            - (indexCatalogDomain2.getSort() == null ? 0 : indexCatalogDomain2.getSort());
                    })
                .collect(Collectors.toList());

        return collect;
    }

    @Override
    public IndexCatalogDomain getIndexCatalogById(Long id) {

        IndexCatalog byId = indexCatalogService.getById(id);
        if (id == 0L) {
            IndexCatalogDomain indexCatalogDomain = new IndexCatalogDomain();
            indexCatalogDomain.setName("全部分组");
            return indexCatalogDomain;
        }
        if (null == byId) {
            return null;
        }
        IndexCatalogDomain indexCatalogDomain =
            ConvertUtil.copyProperties(byId, IndexCatalogDomain.class);
        return indexCatalogDomain;
    }

    /**
     * @description : 找到目录的子 root 当前目录 all 所有目录
     * @author : tinglan.ys
     * @date : 2022/4/19
     */
    private List<IndexCatalogDomain> getChildrens(
        IndexCatalogDomain root, List<IndexCatalogDomain> all) {

        List<IndexCatalogDomain> children =
            all.stream()
                .filter(indexCatalogDomain -> indexCatalogDomain.getPid().equals(root.getId()))
                .map(
                    indexCatalogDomain -> {
                        // 找到子菜单
                        indexCatalogDomain.setChildren(getChildrens(indexCatalogDomain, all));
                        return indexCatalogDomain;
                    })
                .sorted(
                    (indexCatalogDomain1, indexCatalogDomain2) -> {
                        return (indexCatalogDomain1.getSort() == null ? 0 : indexCatalogDomain1.getSort())
                            - (indexCatalogDomain2.getSort() == null ? 0 : indexCatalogDomain2.getSort());
                    })
                .collect(Collectors.toList());

        return children;
    }

    //    @BizDataIndexAnnotation(
//        type = BizDataIndexTypeEnum.INDEX_LIB,
//        dataIdFieldName = "pid",
//        dataIdParamIndex = 0,
//        operateType = BizDataIndexAnnotation.OperateType.SAVE)
    @Override
    public Boolean addCatalog(String name, Long projectId, Long pid) {

        // 同名目录校验
    /*    Query query = new Query(Criteria.where("projectId").is(projectId).and("name").is(name));
    long count = indexCatalogMapper.count(query);
    if (count > 0) {
      throw new BusinessException("该空间存在同名目录");
    }*/

        IndexCatalog indexCatalog = new IndexCatalog();
        indexCatalog.setName(name);
        // pid为空, 或者在全部分组下新建
        if (pid == null || pid == 0) {
            // 没有父，级别为1 pid为0
            indexCatalog.setLevel(1);
            indexCatalog.setPid(0L);
        } else {
            // 有父  级别为父的级别+1
            indexCatalog.setLevel(indexCatalogService.getById(pid).getLevel() + 1);
            indexCatalog.setPid(pid);
        }
        indexCatalog.setShowStatus(1);
        indexCatalog.setProjectId(projectId);
        // 前端没有穿排序这个字段，全部存0吧
        indexCatalog.setSort(0);
        indexCatalogService.save(indexCatalog);
        return true;
    }

    @Override
    public Boolean editCatalog(String name, Long id) {
        IndexCatalog indexCatalog = new IndexCatalog();
        indexCatalog.setId(id);
        indexCatalog.setName(name);
        indexCatalogService.saveOrUpdate(indexCatalog);
        return true;
    }

    //    @BizDataIndexAnnotation(
//        type = BizDataIndexTypeEnum.INDEX_LIB,
//        dataIdFieldName = "id",
//        dataIdParamIndex = 0,
//        operateType = BizDataIndexAnnotation.OperateType.DELETE)
    @Override
    public Boolean delCatalog(Long id) {
        // 查询该目录是否存在子

        long count =
            indexCatalogService.count(
                new LambdaQueryWrapper<IndexCatalog>().eq(IndexCatalog::getPid, id));

        if (count > 0) {
            throw new BusinessException("该目录存在子目录，无法删除");
        }

        long count1 =
            indexService.count(
                new LambdaQueryWrapper<IndexEntity>().eq(IndexEntity::getIndexCatalogId, id));

        if (count1 > 0) {
            throw new BusinessException("该目录被指标引用，无法删除");
        }

        indexCatalogService.removeById(id);

        return true;
    }

    //    @BizDataIndexAnnotation(
//        type = BizDataIndexTypeEnum.INDEX_LIB,
//        dataIdFieldName = "id",
//        dataIdParamIndex = 0,
//        operateType = BizDataIndexAnnotation.OperateType.SAVE)
    @Override
    public Boolean addIndex(IndexParam indexParam) {
        IndexEntity indexEntity = ConvertUtil.copyProperties(indexParam, IndexEntity.class);
        if (indexEntity.getId() != null) {
            // 前端传入id，走更新逻辑
            IndexEntity oldIndex = indexService.getById(indexParam.getId());

            // 做唯一性校验，编辑的时候 在相同的目录下，不能存在相同的指标名称（同一指标不同版本的name是可以一样的）

            LambdaQueryWrapper<IndexEntity> queryWrapper =
                new LambdaQueryWrapper<IndexEntity>()
                    .eq(IndexEntity::getProjectId, indexParam.getProjectId())
                    .eq(IndexEntity::getIndexCatalogId, indexParam.getIndexCatalogId())
                    .eq(IndexEntity::getName, indexParam.getName())
                    .ne(IndexEntity::getIndexNum, oldIndex.getIndexNum());

            long count = indexService.count(queryWrapper);

            if (count > 0) {
                throw new BusinessException("在相同的目录下，不能存在相同的指标名称");
            }
            indexEntity.setUpdaterId(UserContext.getUserId());
            indexService.saveOrUpdate(indexEntity);
//            LogContext.put(LogKey.NAME.getKey(), indexEntity.getName());
            return true;
        }
        // 新增逻辑
        // 首先做唯一性校验，在相同的目录下，不能存在相同的指标名称

        LambdaQueryWrapper<IndexEntity> queryWrapper =
            new LambdaQueryWrapper<IndexEntity>()
                .eq(IndexEntity::getProjectId, indexParam.getProjectId())
                .eq(IndexEntity::getIndexCatalogId, indexParam.getIndexCatalogId())
                .eq(IndexEntity::getName, indexParam.getName());

        long count = indexService.count(queryWrapper);
        if (count > 0) {
            throw new BusinessException("在相同的目录下，不能存在相同的指标名称");
        }

        // 新增指标默认版本号是V1.0
        // 使用时间戳给每一个指标建立一个编号
        long timeStamp = System.currentTimeMillis();
        indexEntity.setIndexNum(timeStamp);
        indexEntity.setVersion("V1.0");
        indexEntity.setStatus(0);
        indexEntity.setCreatorId(UserContext.getUserId());
        indexEntity.setUpdaterId(UserContext.getUserId());
        indexService.saveOrUpdate(indexEntity);
//        LogContext.put(LogKey.NAME.getKey(), indexEntity.getName());
//        LogContext.put(LogKey.ISUPDATE.getKey(), LogKey.ISUPDATE.getValue());
        indexParam.setId(indexEntity.getId());
        return true;
    }

    //    @BizDataIndexAnnotation(
//        type = BizDataIndexTypeEnum.INDEX_LIB,
//        dataIdFieldName = "id",
//        dataIdParamIndex = 0,
//        operateType = BizDataIndexAnnotation.OperateType.SAVE)
    @Override
    public Boolean addIndexVersion(IndexParam indexParam) {

        if (indexParam.getIndexNum() == null) {
            throw new BusinessException("请传入老版本的指标编号");
        }

        LambdaQueryWrapper<IndexEntity> queryWrapper =
            new LambdaQueryWrapper<IndexEntity>()
                .eq(IndexEntity::getIndexNum, indexParam.getIndexNum())
                .orderByDesc(IndexEntity::getCreateTime);

        // 得到最新的版本
        IndexEntity indexEntityNewest = indexService.list(queryWrapper).get(0);

        if (indexEntityNewest.getStatus() == 0) {
            throw new BusinessException("该指标的最新版本尚未完成，无法新增该指标的更高版本");
        }

        IndexEntity indexEntity = ConvertUtil.copyProperties(indexParam, IndexEntity.class);
        indexEntity.setVersion(addVersion(indexEntityNewest.getVersion()));
        indexEntity.setStatus(0);

        indexService.saveOrUpdate(indexEntity);

        return true;
    }

    /**
     * 找同级
     *
     * @param projectId
     * @param level
     * @return
     */
    @Override
    public List<Long> getAllIndexCatalogByLevel(Long projectId, int level) {

        LambdaQueryWrapper<IndexCatalog> queryWrapper =
            new LambdaQueryWrapper<IndexCatalog>()
                .eq(IndexCatalog::getProjectId, projectId)
                .eq(IndexCatalog::getLevel, level);

        List<IndexCatalog> byProjectIdAndLevel = indexCatalogService.list(queryWrapper);

        return byProjectIdAndLevel.stream().map(IndexCatalog::getId).collect(Collectors.toList());
    }

    /**
     * 支持全部目录
     *
     * @param pIds
     * @param projectId
     * @description : 获取某个目录下所有的子
     * @author : tinglan.ys
     * @date : 2022/4/22
     */
    @Override
    public List<Long> getAllChildIdByMultiPid(List<Long> pIds, Long projectId) {

        // 1 查询所有分类
        List<IndexCatalog> indexCatalogList =
            indexCatalogService.list(
                new LambdaQueryWrapper<IndexCatalog>().eq(IndexCatalog::getProjectId, projectId));

        List<IndexCatalogDomain> all =
            ConvertUtil.copyProperties(indexCatalogList, IndexCatalogDomain.class);
        // 2. 查询根节点

        LambdaQueryWrapper<IndexCatalog> queryWrapper =
            new LambdaQueryWrapper<IndexCatalog>().eq(IndexCatalog::getProjectId, projectId);
        if (CollectionUtils.isNotEmpty(pIds)) {
            queryWrapper.in(IndexCatalog::getPid, pIds);
        }
        List<IndexCatalog> byPids = indexCatalogService.list(queryWrapper);
        List<IndexCatalogDomain> roots = ConvertUtil.copyProperties(byPids, IndexCatalogDomain.class);
        List<Long> rootIds = roots.stream().map(IndexCatalogDomain::getId).collect(Collectors.toList());

        // 定义ids
        List<Long> catalogIds = new LinkedList<>(rootIds);

        all.stream()
            .filter(indexCatalogDomain -> rootIds.contains(indexCatalogDomain.getPid()))
            .forEach(
                indexCatalogDomain -> {
                    // 找到子菜单
                    indexCatalogDomain.setChildren(getChildrens(indexCatalogDomain, all));
                    // 将子菜单的id存到局部变量中
                    catalogIds.add(indexCatalogDomain.getId());
                });

        return catalogIds;
    }

    /**
     * @param catalogId
     * @param projectId
     * @description : 获取某个目录下所有的子
     * @author : tinglan.ys
     * @date : 2022/4/22
     */
    @Override
    public List<Long> getAllChildIdByPid(Long catalogId, Long projectId) {

        // 1 查询所有分类

        List<IndexCatalog> indexCatalogList =
            indexCatalogService.list(
                new LambdaQueryWrapper<IndexCatalog>().eq(IndexCatalog::getProjectId, projectId));

        List<IndexCatalogDomain> all =
            ConvertUtil.copyProperties(indexCatalogList, IndexCatalogDomain.class);
        // 2. 查询根节点
        if (catalogId == 0) {
            // 如果选择的是全部分组，返回所有id
            return indexCatalogList.stream().map(IndexCatalog::getId).collect(Collectors.toList());
        }

        IndexCatalog byId = indexCatalogService.getById(catalogId);
        IndexCatalogDomain root = ConvertUtil.copyProperties(byId, IndexCatalogDomain.class);

        // 定义ids
        List<Long> catalogIds = new ArrayList<>();
        catalogIds.add(root.getId());

        // 跑一下找子的方法
        List<IndexCatalogDomain> children =
            all.stream()
                .filter(indexCatalogDomain -> indexCatalogDomain.getPid().equals(root.getId()))
                .map(
                    indexCatalogDomain -> {
                        // 找到子菜单
                        indexCatalogDomain.setChildren(getChildrens(indexCatalogDomain, all));
                        // 将子菜单的id存到局部变量中
                        catalogIds.add(indexCatalogDomain.getId());
                        return indexCatalogDomain;
                    })
                .collect(Collectors.toList());

        return catalogIds;
    }

    @Override
    public PageResult<IndexDomain> indexList(IndexListParam indexListParam) {

        LambdaQueryWrapper<IndexEntity> queryWrapper =
            new LambdaQueryWrapper<IndexEntity>()
                .eq(IndexEntity::getProjectId, indexListParam.getProjectId())
                .eq(
                    null != indexListParam.getThemeId(),
                    IndexEntity::getThemeId,
                    indexListParam.getThemeId())
                .in(
                    CollectionUtils.isNotEmpty(indexListParam.getCatalogIdList()),
                    IndexEntity::getIndexCatalogId,
                    indexListParam.getCatalogIdList())
                .like(
                    StringUtils.isNotBlank(indexListParam.getName()),
                    IndexEntity::getName,
                    indexListParam.getName())
                .eq(
                    indexListParam.getStatus() != null,
                    IndexEntity::getStatus,
                    indexListParam.getStatus())
                .orderByDesc(IndexEntity::getCreateTime);
        List<IndexEntity> indexEntityList = indexService.list(queryWrapper);

        List<IndexDomain> indexDomains = Lists.newArrayList();
        indexEntityList.forEach(
            e -> {
                IndexDomain convert = Convert.convert(IndexDomain.class, e);
                IndexCorrelation indexCorrelation = new IndexCorrelation();
                indexCorrelation.setTblId(e.getTblId());
                indexCorrelation.setTblName(e.getTblName());
                convert.setIndexCorrelation(indexCorrelation);
                indexDomains.add(convert);
            });

        // 拼装ownerName  并且这里做个分组 根据指标编号
        Map<Long, List<IndexDomain>> indexMap =
            indexDomains.stream()
                .map(
                    indexDomain -> {
//                        DataOwnerEntity dataOwnerEntity =
//                            dataOwnerService.getById(indexDomain.getDataOwnerId());
//                        if (dataOwnerEntity != null) {
//                            String ownerName = dataOwnerEntity.getOwnerName();
//                            indexDomain.setDataOwnerName(ownerName);
//                        }
                        return indexDomain;
                    })
                .collect(Collectors.groupingBy(indexDomain -> indexDomain.getIndexNum()));

        // 定义前端传入版本号，拿到的指标数据。（根据版本号匹配到的list，前端不把每个指标每个版本传过来的话不全）
        List<IndexDomain> indexDomainList = new ArrayList<>();
        // 定义前端不传，拿到最新的版本指标数据。这个是全部数据。
        List<IndexDomain> indexDomainListWithoutVersion = new ArrayList<>();

        Set<Long> indexNumList = indexMap.keySet();

        for (Long indexNum : indexNumList) {
            // 得到每个指标编号的指标list，从中筛选指定版本号的指标的记录。
            List<IndexDomain> indexDomainListOfIndexNum = indexMap.get(indexNum);
            // 获取这个这个表号的指标共有多少个版本信息 versionList
            List<String> versionList =
                indexDomainListOfIndexNum.stream()
                    .map(indexDomain -> indexDomain.getVersion())
                    .collect(Collectors.toList());
            // 把versionList信息塞到每一条指标里
            for (IndexDomain indexDomain : indexDomainListOfIndexNum) {
                indexDomain.setVersionList(versionList);
            }

            // 先把没有指定版本号的情况查出来indexDomainListWithoutVersion。
            // 传版本号的情况，无非是用indexDomainList替换先把没有指定版本号的情况查出来indexDomainListWithoutVersion的几条数据。

            // 如果没有指定版本号，那么取版本号最新的作为返回的结果集合, 因为查询的时候根据创建时间排序，所以取第一条就是
            indexDomainListWithoutVersion.add(indexDomainListOfIndexNum.get(0));

            if (CollectionUtils.isNotEmpty(indexListParam.getVersionParams())) {
                // 如果指定版本号
                // 1.获取版本信息
                List<IndexListParam.VersionParam> versionParams = indexListParam.getVersionParams();
                for (IndexListParam.VersionParam versionParam : versionParams) {
                    // 2.如果当前指标编号和传入进来的版本信息对上了
                    if (versionParam.getIndexNum().equals(indexNum)) {
                        // 3.取指定版本的那条记录
                        for (IndexDomain indexDomain : indexDomainListOfIndexNum) {
                            if (indexDomain.getVersion().equals(versionParam.getVersion())) {
                                indexDomainList.add(indexDomain);
                            }
                        }
                    } else {
                        // 4.如果当前指标编号和传入进来的版本信息没有对上，且indexDomainList中没有该指标编号的记录 那么返回最新版本号最高的记录，这个逻辑好像有问题？
                        // indexDomainList.add(indexDomainListOfIndexNum.get(0));
                    }
                }
            }
        }

        if (CollectionUtils.isNotEmpty(indexDomainList)) {
            // 如果指定版本查出来的数据有值，将非指定版本的数据做一个替换
            for (int i = 0; i < indexDomainListWithoutVersion.size(); i++) {
                for (int j = 0; j < indexDomainList.size(); j++) {
                    if (indexDomainListWithoutVersion
                        .get(i)
                        .getIndexNum()
                        .equals(indexDomainList.get(j).getIndexNum())) {
                        indexDomainListWithoutVersion.set(i, indexDomainList.get(j));
                    }
                }
            }
        }

        // 根据时间重新排序
        indexDomainListWithoutVersion.sort(
            (o1, o2) -> {
                try {
                    Date dt1 = o1.getUpdateTime();
                    Date dt2 = o2.getUpdateTime();
                    if (dt1.getTime() < dt2.getTime()) {
                        return 1;
                    } else if (dt1.getTime() > dt2.getTime()) {
                        return -1;
                    } else {
                        return 0;
                    }
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
                return 0;
            });

        if (CollectionUtils.isNotEmpty(indexDomainListWithoutVersion)) {
            List<String> userId =
                indexDomainListWithoutVersion.stream()
                    .map(BaseDomain::getCreatorId)
                    .collect(Collectors.toList());
            Map<String, String> mapByUserIds = userService.getMapByUserIds(userId);
            for (IndexDomain item : indexDomainListWithoutVersion) {
                item.setCreator(mapByUserIds.getOrDefault(item.getCreatorId(), ""));
            }
        }

        PageResult<IndexDomain> result =
            new PageResult<>(
                indexDomainListWithoutVersion,
                indexListParam.getPageNum(),
                indexListParam.getPageSize());

        return result;
    }

    @Override
    public Map<Long, List<IndexDomain>> indexList2(
        String projectId,
        List<String> catalogIdList,
        String name,
        Short status,
        Integer pageNum,
        Integer pageSize) {

        LambdaQueryWrapper<IndexEntity> queryWrapper =
            new LambdaQueryWrapper<IndexEntity>()
                .eq(IndexEntity::getProjectId, projectId)
                .in(
                    CollectionUtils.isNotEmpty(catalogIdList),
                    IndexEntity::getIndexCatalogId,
                    catalogIdList)
                .like(StringUtils.isNotBlank(name), IndexEntity::getName, name)
                .eq(status != null, IndexEntity::getStatus, status)
                .orderByDesc(IndexEntity::getCreateTime);

        List<IndexEntity> indexEntityList = indexService.list(queryWrapper);
        List<IndexDomain> indexDomains = ConvertUtil.copyProperties(indexEntityList, IndexDomain.class);
        // 拼装ownerName  并且这里做个分组 根据指标编号

        Map<Long, List<IndexDomain>> indexMap =
            indexDomains.stream()
                .map(
                    indexDomain -> {
//                        DataOwnerEntity dataOwnerEntity =
//                            dataOwnerService.getById(indexDomain.getDataOwnerId());
//                        if (dataOwnerEntity != null) {
//                            String ownerName = dataOwnerEntity.getOwnerName();
//                            indexDomain.setDataOwnerName(ownerName);
//                        }
                        return indexDomain;
                    })
                .collect(Collectors.groupingBy(IndexDomain::getIndexNum));

        return indexMap;
    }

    @Override
    public IndexDomain indexDetail(Long id) {
        IndexEntity byId = indexService.getById(id);
        IndexDomain indexDomain = ConvertUtil.copyProperties(byId, IndexDomain.class);
//        DataOwnerEntity dataOwnerEntity = dataOwnerService.getById(indexDomain.getDataOwnerId());
//        if (dataOwnerEntity != null) {
//            String ownerName = dataOwnerEntity.getOwnerName();
//            indexDomain.setDataOwnerName(ownerName);
//        }
        return indexDomain;
    }

    //    @BizDataIndexAnnotation(
//        type = BizDataIndexTypeEnum.INDEX_LIB,
//        dataIdFieldName = "id",
//        dataIdParamIndex = 0,
//        operateType = BizDataIndexAnnotation.OperateType.DELETE)
    @Override
    public Boolean delIndex(Long id) {
        indexService.removeById(id);
        return true;
    }

    @Override
    public List<TableInfoBizDomain> getTableList(Long projectId) {
        QueryTableParam queryTableParam = new QueryTableParam();
        queryTableParam.setSortField("UPDATETIME");
        queryTableParam.setOrder("desc");
        List<TableInfoBizDomain> tableList = tableService.getTableList(projectId, queryTableParam);
        DataSourceDomain systemDataSourceByProjectId = dataSourceService.getSystemDataSourceByProjectId(
            projectId);
        if (systemDataSourceByProjectId.getDsType().equalsIgnoreCase(DSType.DM.name())) {
            for (TableInfoBizDomain tableInfoBizDomain : tableList) {
                if (StringUtils.isNotBlank(tableInfoBizDomain.getSchema())) {
                    tableInfoBizDomain.setTableName(
                        tableInfoBizDomain.getSchema() + "." + tableInfoBizDomain.getTableName());
                }
            }
        }

        return tableList;
    }

    public static void main(String[] args) {
        //
        List<List<Object>> rows = new ArrayList<>();

        List<Object> row1 = Arrays.asList("dfd", null, null);
        List<Object> row2 = Arrays.asList("dsfds", null, "sdf");
        rows.add(row1);
        rows.add(row2);
        if (CollectionUtils.isNotEmpty(rows)) {
            for (int i = 1; i <= rows.size(); i++) {
                System.out.println("创建行1");
                for (int j = 0; j < rows.get(i - 1).size(); j++) {
                    Object val = rows.get(i - 1).get(j);
                    if (val != null) {
                        System.out.println("rows.get(i - 1).get(j).toString() = " + val.toString());
                    }
                }
            }
        }
    }

    @Override
    public void indexListExport(HttpServletResponse response, PreviewDataParam previewDataParam)
        throws IOException {
        // 创建工作薄对象 这里也可以设置sheet的Name
        XSSFWorkbook workbook = new XSSFWorkbook();
        // 创建工作表对象
        XSSFSheet sheet = workbook.createSheet();
        // 创建工作表的第一行
        // 设置第一行，从零开始 列信息
        XSSFRow row = sheet.createRow(0);
        List<String> columns = previewDataParam.getColumns();
        for (int i = 0; i < columns.size(); i++) {
            row.createCell(i).setCellValue(columns.get(i));
        }

        // 数据信息
        List<List<Object>> rows = previewDataParam.getRows();
        if (CollectionUtils.isNotEmpty(rows)) {
            for (int i = 1; i <= rows.size(); i++) {
                XSSFRow row1 = sheet.createRow(i);
                for (int j = 0; j < rows.get(i - 1).size(); j++) {
                    Object val = rows.get(i - 1).get(j);
                    if (val != null) {
                        row1.createCell(j).setCellValue(val.toString());
                    }
                }
            }
        }

        LocalDateTime localDateTime = LocalDateTime.now();
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String time = df.format(localDateTime);

        workbook.setSheetName(0, "指标结果"); // 设置sheet的Name

        // 创建response输出流
        OutputStream os = response.getOutputStream();
        // 重置输出流
        response.reset();
        String filename = "指标结果" + time + ".xlsx";
        // 定义输出类型
        response.setContentType("application/msexcel");
        // 设定输出文件头
        response.setHeader(
            "Content-disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
        workbook.write(os);
        os.flush();
        os.close();
    }

    //    @BizDataIndexAnnotation(
//        type = BizDataIndexTypeEnum.INDEX_LIB,
//        dataIdFieldName = "id",
//        dataIdParamIndex = 0,
//        operateType = BizDataIndexAnnotation.OperateType.SAVE)
    @Override
    public Boolean saveIndexCorrelation(Long id, String tblName, Long tblId) {
        IndexEntity indexEntity = new IndexEntity();
        indexEntity.setId(id);
        indexEntity.setTblId(tblId);
        indexEntity.setTblName(tblName);
        if (tblId == null && tblName == null) {
            // 如果关联内容都为空，就表示取消关联
            this.indexService.update(
                new LambdaUpdateWrapper<IndexEntity>()
                    .eq(IndexEntity::getId, id)
                    .set(IndexEntity::getTblId, null)
                    .set(IndexEntity::getTblName, null)
                    .set(IndexEntity::getStatus, 0));
        } else {
            indexEntity.setStatus(1);
            indexService.saveOrUpdate(indexEntity);
        }
        return true;
    }

    @Override
    public Boolean updateByIdSelective(IndexEntity indexEntity) {
        indexService.saveOrUpdate(indexEntity);
        return true;
    }

    @Override
    public List<IndexBaseDomain> getIndexPublished(Long projectId, List<Long> dirList) {

        LambdaQueryWrapper<IndexEntity> queryWrapper =
            new LambdaQueryWrapper<IndexEntity>()
                .eq(IndexEntity::getProjectId, projectId)
                .eq(IndexEntity::getStatus, 1)
                .orderByDesc(IndexEntity::getCreateTime);
        if (CollectionUtils.isNotEmpty(dirList)) {
            queryWrapper.in(IndexEntity::getIndexCatalogId, dirList);
        }

        List<IndexEntity> indexEntityList = indexService.list(queryWrapper);
        // 同一个指标不同的版本，只取最高的版本
        // 这里做个分组 根据指标编号
        Map<Long, List<IndexEntity>> indexMap =
            indexEntityList.stream()
                .collect(Collectors.groupingBy(indexEntity -> indexEntity.getIndexNum()));

        List<IndexEntity> indexEntityListNew = new ArrayList<>();
        for (Long indexNum : indexMap.keySet()) {
            // 只要塞入第一条就行，因为第一条是创建时间最新的 也就是版本最高的
            indexEntityListNew.add(indexMap.get(indexNum).get(0));
        }

        DataSourceEntity systemDataSourceDetail =
            dataSourceService.getSystemDataSourceDetail(projectId);
        List<IndexBaseDomain> r1 =
            indexEntityListNew.stream()
                .filter(e -> e.getTblId() != null || e.getTblName() != null)
                .map(
                    e -> {
                        IndexBaseDomain indexBaseDomain = new IndexBaseDomain();
                        indexBaseDomain.setIndexId(e.getId());
                        indexBaseDomain.setName(e.getName() + " " + e.getVersion());
                        indexBaseDomain.setTblId(e.getTblId());
                        indexBaseDomain.setDsId(systemDataSourceDetail.getId());
                        indexBaseDomain.setTblName(e.getTblName());
                        return indexBaseDomain;
                    })
                .collect(Collectors.toList());

        return r1;
    }

    @Override
    public List<AssociatedTaskDomain> getAssociatedTasks(String tableName, Long projectId) {

        List<AssociatedTaskDomain> associatedTaskDomains = new ArrayList<>();

        //  1.离线同步任务
        List<OfflineSyncDomain> offlineTask = offlineSyncService.getOfflineTask(projectId, tableName);
        if (CollectionUtils.isNotEmpty(offlineTask)) {
            for (OfflineSyncDomain offlineSyncDomain : offlineTask) {
                AssociatedTaskDomain associatedTaskDomain = new AssociatedTaskDomain();
                associatedTaskDomain.setOfflineSyncId(offlineSyncDomain.getId());
                associatedTaskDomain.setTaskName(offlineSyncDomain.getTaskName());
                associatedTaskDomains.add(associatedTaskDomain);
            }
        }

        //  2.离线开发任务 产出表:tableProduct 找到离线开发任务
        // TODO: 查找离线开发任务
//        Set<String> addDiff = Sets.newHashSet();
//        TblPropEntity tblPropByTblName = tblPropService.getTblPropByTblName(projectId, tableName);
//        if (tblPropByTblName != null) {
//            List<TableProductDomain> tableProductDomains =
//                tableProductService.getTableProductDomain(tblPropByTblName.getTblId(), projectId);
//            if (CollectionUtils.isNotEmpty(tableProductDomains)) {
//                for (TableProductDomain tableProductDomain : tableProductDomains) {
//
//                    String diff =
//                        tableProductDomain.getTaskFlowId() + "-" + tableProductDomain.getSubTaskId();
//                    if (addDiff.contains(diff)) {
//                        continue;
//                    }
//                    addDiff.add(diff);
//                    AssociatedTaskDomain associatedTaskDomain = new AssociatedTaskDomain();
//                    associatedTaskDomain.setNodeId(tableProductDomain.getTaskFlowId());
//                    associatedTaskDomain.setTaskName(tableProductDomain.getTaskFlowName());
//                    associatedTaskDomains.add(associatedTaskDomain);
//                }
//            }
//        }

        //  3.文件采集任务 找到文件采集任务 document_capture_entity
        List<DocumentCaptureDomain> docTask = documentCaptureService.getDocTask(projectId, tableName);
        if (CollectionUtils.isNotEmpty(docTask)) {
            for (DocumentCaptureDomain documentCaptureDomain : docTask) {
                AssociatedTaskDomain associatedTaskDomain = new AssociatedTaskDomain();
                associatedTaskDomain.setDocumentCaptureId(documentCaptureDomain.getId());
                associatedTaskDomain.setTaskName("文件采集任务:" + documentCaptureDomain.getOrgFileName());
                associatedTaskDomains.add(associatedTaskDomain);
            }
        }

        //  4.自定义表单 任务名就是表单名
//        List<CustomFormDomain> formTasks = customFormService.getFormTask(projectId, tableName);
//        if (CollectionUtils.isNotEmpty(formTasks)) {
//            for (CustomFormDomain formTask : formTasks) {
//                AssociatedTaskDomain associatedTaskDomain = new AssociatedTaskDomain();
//                associatedTaskDomain.setTaskName("自定义表单:" + formTask.getTitle());
//                associatedTaskDomain.setCustomFormId(formTask.getId());
//            }
//        }

        return associatedTaskDomains;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "engineTransactionManager")
    public String alarmDisassociate(Long projectId, Long indexId) {

        List<DataApiEntity> dataApiEntities = dataApiService.findByProjectIdIndexId(projectId, indexId);
        if (CollectionUtils.isNotEmpty(dataApiEntities)) {
            List<String> nameList =
                dataApiEntities.stream()
                    .map(dataApiEntity -> dataApiEntity.getApiName())
                    .collect(Collectors.toList());

            String alarmInfo =
                "已被数据服务:" + String.join(",", nameList) + "引用，变更关联表会导致数据服务出错";
            return alarmInfo;
        }
        return "已成功取消关联";
    }

    @Override
    public List<IndexForAbacusDomain> getIndexForAbacus(Long userId) {

        // 1. 根据userId 查询该用户拥有的空间 如果是管理员用户拥有所有空间

        List<Long> projectIds = new ArrayList<>();
        if (userId == 1) {
            List<ProjectDomain> allProject = projectService.getAllProject();
            List<Long> allProjectIds =
                allProject.stream()
                    .map(projectDomain -> projectDomain.getId())
                    .collect(Collectors.toList());
            projectIds = allProjectIds;

        } else {
            Set members = redisTemplate.opsForSet().members("UserAuthOfUser:" + userId);
            if (CollectionUtils.isEmpty(members)) {
                throw new BusinessException("该用户不存在工作空间");
            }
            projectIds.addAll(members);
        }

        List<IndexForAbacusDomain> indexForAbacusDomains = new ArrayList<>();
        for (Long projectId : projectIds) {
            IndexForAbacusDomain indexForAbacusDomain = new IndexForAbacusDomain();
            // 2. 塞入相关信息
            indexForAbacusDomain.setProjectId(projectId);

            List<IndexCatalogDomain> indexCatalogDomains = this.listCatalogWithTree(projectId);
            indexForAbacusDomain.setIndexCatalog(indexCatalogDomains);

            List<IndexEntity> indexEntityList =
                indexService.list(
                    new LambdaQueryWrapper<IndexEntity>()
                        .eq(IndexEntity::getProjectId, projectId)
                        .orderByDesc(IndexEntity::getCreateTime));

            List<IndexDomain> indexDomainList =
                ConvertUtil.copyProperties(indexEntityList, IndexDomain.class);
            if (CollectionUtils.isNotEmpty(indexDomainList)) {
                for (IndexDomain indexDomain : indexDomainList) {
                    // 该指标对应的数据服务的接口地址
                    List<DataApiEntity> dataApiEntities =
                        dataApiService.findByProjectIdIndexId(projectId, indexDomain.getId());
                    if (CollectionUtils.isNotEmpty(dataApiEntities)) {
                        List<String> apiPathList =
                            dataApiEntities.stream()
                                .map(dataApiEntity -> dataApiEntity.getApiPath())
                                .collect(Collectors.toList());
                        indexDomain.setApiPathList(apiPathList);
                    }
                }
            }
            indexForAbacusDomain.setIndexDomain(indexDomainList);
            indexForAbacusDomains.add(indexForAbacusDomain);
        }

        return indexForAbacusDomains;
    }

    /**
     * @description : 版本号+1
     * @author : tinglan.ys
     * @date : 2022/4/22
     */
    private static String addVersion(String oldVersion) {
        int oldNum = Integer.parseInt(oldVersion.replace("V", "").replace(".", ""));
        oldNum++;
        // 这样为保持1位
        double newNum = (Math.round(oldNum) / 10.0);
        return "V" + newNum;
    }

    /**
     * 算盘cdm左侧表开发
     *
     * @param projectId
     * @return
     */
    @Override
    public List<QuotaDevSourceTableDomain> getDevSourceTable(Long projectId, Long themeId) {
        List<TblPropEntity> dwdList =
            this.tblPropService.getCdmQuotaSourceTable(projectId, themeId, "dwd");
        List<QuotaDevSourceTableDomain> result = new ArrayList<>();
        for (TblPropEntity tblPropEntity : dwdList) {
            QuotaDevSourceTableDomain quotaDevSourceTableDomain = new QuotaDevSourceTableDomain();
            quotaDevSourceTableDomain.setTblId(tblPropEntity.getTblId());
            quotaDevSourceTableDomain.setName(tblPropEntity.getTableName());
            quotaDevSourceTableDomain.setDesc(tblPropEntity.getTableComment());
            result.add(quotaDevSourceTableDomain);
        }
        return result;
    }

    /**
     * 算盘cdm左侧表开发
     *
     * @param projectId
     * @return
     */
    @Override
    public List<QuotaDevSourceTableFieldDomain> getDevSourceTableField(Long projectId, Long tblId) {
        ModelDomain modelByTblId = modelService.getModelByTblId(projectId, tblId);
        List<ModelDomain.Field> fields = modelByTblId.getFields();
        List<QuotaDevSourceTableFieldDomain> result = new ArrayList<>();
        for (ModelDomain.Field field : fields) {
            QuotaDevSourceTableFieldDomain quotaDevSourceTableFieldDomain =
                new QuotaDevSourceTableFieldDomain();
            quotaDevSourceTableFieldDomain.setFieldName(field.getFieldName());
            quotaDevSourceTableFieldDomain.setFieldType(field.getFieldType());
            quotaDevSourceTableFieldDomain.setFieldComment(field.getFieldDesc());
            result.add(quotaDevSourceTableFieldDomain);
        }
        return result;
    }

    /**
     * 保存cdm指标开发
     *
     * @param indexDevParam
     */
    @Override
    public void saveDev(IndexDevParam indexDevParam) {
        // TODO:
        // 已有指标表开发
        throw new NotImplementedException();
//        if (indexDevParam.getDevType() == 1) {
//            String tblName = indexDevParam.getTblName();
//            String indexField = indexDevParam.getIndexField();
//            this.indexService.update(
//                new LambdaUpdateWrapper<IndexEntity>()
//                    .set(IndexEntity::getStatus, 1)
//                    .set(IndexEntity::getDevType, 1)
//                    .set(IndexEntity::getTblId, indexDevParam.getTblId())
//                    .set(IndexEntity::getTblName, tblName)
//                    .set(IndexEntity::getIndexField, indexField)
//                    .eq(IndexEntity::getId, indexDevParam.getId()));
//            return;
//        }
//
//        // 新建表开发-依赖调度
//        if (indexDevParam.getTriggerType() == 1) {
//            String tblName = indexDevParam.getTblName();
//            // 指标字段
//            String indexField = indexDevParam.getIndexField();
//            this.indexService.update(
//                new LambdaUpdateWrapper<IndexEntity>()
//                    .set(IndexEntity::getStatus, 1)
//                    .set(IndexEntity::getDevType, 0)
//                    .set(IndexEntity::getTriggerType, 1)
//                    .set(IndexEntity::getTblId, indexDevParam.getTblId())
//                    .set(IndexEntity::getTblName, tblName)
//                    .set(IndexEntity::getIndexField, indexField)
//                    .eq(IndexEntity::getId, indexDevParam.getId()));
//            return;
//        }
//
//        // 新建表开发-定时调度
//        OfflineDevTaskFlowVNodeConfigSaveParam schedule =
//            ConvertUtil.copyProperties(indexDevParam, OfflineDevTaskFlowVNodeConfigSaveParam.class);
//
//        if (null == schedule.getNodeId() || null == schedule.getCycleDependency()) {
//            throw new BusinessException("定时调度参数错误");
//        }
//
//        Boolean scheduleResult =
//            offlineDevMenuNodeService.saveTaskFlowSchedule(
//                schedule, indexDevParam.getProjectId(), indexDevParam.getUserId());
//
//        if (Boolean.TRUE != scheduleResult) {
//            throw new BusinessException("定时调度保存失败");
//        }
//        String indexField = indexDevParam.getIndexField();
//        this.indexService.update(
//            new LambdaUpdateWrapper<IndexEntity>()
//                .set(IndexEntity::getStatus, 1)
//                .set(IndexEntity::getDevType, 0)
//                .set(IndexEntity::getTriggerType, 0)
//                .set(IndexEntity::getTblName, indexDevParam.getTblName())
//                .set(IndexEntity::getIndexField, indexField)
//                .eq(IndexEntity::getId, indexDevParam.getId()));
    }

    @Override
    public IndexDomain getIndex(Long id) {
        IndexEntity byId = indexService.getById(id);
        IndexDomain indexDomain = ConvertUtil.copyProperties(byId, IndexDomain.class);
//        DataOwnerEntity dataOwnerEntity = dataOwnerService.getById(indexDomain.getDataOwnerId());
//        if (dataOwnerEntity != null) {
//            String ownerName = dataOwnerEntity.getOwnerName();
//            indexDomain.setDataOwnerName(ownerName);
//        }

        String timeGranularity = indexDomain.getTimeGranularity();
        if (StringUtils.isNotBlank(timeGranularity)) {
            try {
                IndexTimeGranularityEnum fromString =
                    EnumUtil.fromString(IndexTimeGranularityEnum.class, timeGranularity.toUpperCase());
                Optional.ofNullable(fromString)
                    .ifPresent(
                        s -> {
                            indexDomain.setTimeGranularityCN(s.getNameCN());
                        });
            } catch (Exception e) {
            }
        }

        return indexDomain;
    }

    /**
     * 获取dev开发配置
     *
     * @param id
     */
    @Override
    public IndexDevParam getDev(Long projectId, Long id) {
        // TODO:
        throw new NotImplementedException();
//        IndexEntity index = this.indexService.getById(id);
//        if (null == index) {
//            throw new BusinessException("指标id不存在");
//        }
//
//        IndexDevParam indexDevParam = new IndexDevParam();
//        indexDevParam.setId(id);
//
//        // 工作流
//        Long taskFlowId = index.getNodeId();
//        indexDevParam.setTaskFlowId(taskFlowId);
//
//        DatadevMenuNodeEntity vnodeByTaskFlowNodeId =
//            offlineDevMenuNodeService.getVnodeByTaskFlowNodeId(taskFlowId);
//        // 开始节点id
//        Long nodeId = vnodeByTaskFlowNodeId.getId();
//        indexDevParam.setNodeId(nodeId);
//        indexDevParam.setProjectId(projectId);
//
//        // sql节点id
//        indexDevParam.setSqlId(index.getSqlId());
//
//        // 没有配置过指标开发
//        if (null == index.getDevType() && null == index.getTriggerType()) {
//            return indexDevParam;
//        }
//
//        if (index.getDevType() == 1) {
//            indexDevParam.setDevType(1);
//            indexDevParam.setTblId(index.getTblId());
//            indexDevParam.setTblName(index.getTblName());
//            indexDevParam.setIndexField(index.getIndexField());
//            return indexDevParam;
//        }
//        // 新建开发-依赖调度
//        if (index.getTriggerType() == 1) {
//            indexDevParam.setDevType(0);
//            indexDevParam.setTriggerType(1);
//            indexDevParam.setTblId(index.getTblId());
//            indexDevParam.setTblName(index.getTblName());
//            indexDevParam.setIndexField(index.getIndexField());
//            return indexDevParam;
//        }
//
//        // 新建开发-定时调度
//        // 调度配置
//        final OfflineDevTaskFlowVNodeDetailDomain taskFlowVNodeDetail =
//            offlineDevMenuNodeService.getTaskFlowVNodeDetail(nodeId, projectId);
//        indexDevParam = ConvertUtil.copyProperties(taskFlowVNodeDetail, IndexDevParam.class);
//        indexDevParam.setProjectId(projectId);
//        indexDevParam.setId(id);
//        indexDevParam.setTaskFlowId(taskFlowId);
//        indexDevParam.setNodeId(nodeId);
//        indexDevParam.setSqlId(index.getSqlId());
//        indexDevParam.setDevType(0);
//        indexDevParam.setTriggerType(0);
//        indexDevParam.setIndexField(index.getIndexField());
//
//        return indexDevParam;
    }

    /**
     * 获取dev脚本开发的字段列表
     *
     * @param id
     */
    @Override
    public List<String> getDevScriptFields(Long projectId, Long id) {
        // TODO:
        throw new NotImplementedException();
        // 获取底层存储
//        StorageEntity storageEntity = storageService.tmpGetStorageInfoByProjectId(projectId);
//        if (null == storageEntity) {
//            throw new BusinessException("请检查工作空间存储");
//        }
//        Database database = Database.from(storageEntity.getStorageType());
//        DbType dbType = null;
//        switch (database) {
//            case HIVE:
//                dbType = JdbcConstants.HIVE;
//                break;
//            case POSTGRESQL:
//                dbType = JdbcConstants.POSTGRESQL;
//                break;
//            case MYSQL:
//                dbType = JdbcConstants.MYSQL;
//                break;
//            case ORACLE:
//                dbType = JdbcConstants.ORACLE;
//                break;
//            default:
//                break;
//        }
//
//        IndexEntity index = this.indexService.getById(id);
//        if (null == index) {
//            throw new BusinessException("指标id不存在");
//        }
//
//        IndexDevParam indexDevParam = new IndexDevParam();
//        indexDevParam.setId(id);
//
//        // sql节点id
//        Long sqlId = index.getSqlId();
//        if (null == sqlId) {
//            throw new BusinessException("sql节点id不存在");
//        }
//
//        // 获取script
//        OfflineDevTaskScriptDetailDomain taskScript =
//            this.offlineDevMenuNodeService.getTaskScript(sqlId, projectId);
//        if (null == taskScript) {
//            throw new BusinessException("sql节点不存在");
//        }
//
//        String script = taskScript.getScript();
//        if (StringUtils.isEmpty(script)) {
//            log.error("请先编辑sql节点");
//            return new ArrayList();
//        }
//
//        // 解析script, 预期从 insert 语句中提取出字段信息
//        try {
//            List<SQLStatement> sqlStatements = SQLUtils.parseStatements(script, dbType);
//            SQLStatement sqlStatement = sqlStatements.get(0);
//            SQLInsertStatement sqlInsertStatement = (SQLInsertStatement) sqlStatement;
//            List<SQLExpr> columns = sqlInsertStatement.getColumns();
//            return columns.stream().map(Object::toString).collect(Collectors.toList());
//        } catch (Exception e) {
//            log.error("sql字段解析异常sql节点");
//            return new ArrayList();
//        }
    }

    /**
     * 创建cdm指标,同时创建taskflow任务,事务操作
     *
     * @param indexParam
     */
    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "engineTransactionManager")
    public void saveCdmIndex(IndexParam indexParam, Long userId) {
        // TODO:
        throw new NotImplementedException();
//        cdmIndexTaskFlowService.addIndex(indexParam);
//        // 手动创建一个任务流
//        String name = indexParam.getName();
//        Long offlineTaskId =
//            cdmIndexTaskFlowService.createOfflineTask(indexParam.getProjectId(), 2L,
//                "CDM指标任务_" + name);
//        // 手动创建一个sql节点
//        Long sqlNodeId =
//            cdmIndexTaskFlowService.createSqlNode(
//                offlineTaskId, "CDM指标任务_sql节点_" + name, indexParam.getProjectId(), userId);
//        // 将sql节点关联到开始节点
//        cdmIndexTaskFlowService.bindStartNode(
//            offlineTaskId, sqlNodeId, indexParam.getProjectId(), userId);
//        // 节点信息保存到index
//        cdmIndexTaskFlowService.initTaskFlow(indexParam.getId(), offlineTaskId, sqlNodeId);
    }

    @Override
    public List<String> getFieldList(Long projectId, Long tblId) {
        ModelDomain modelByTblId = modelService.getModelByTblId(projectId, tblId);
        return modelByTblId.getFields().stream()
            .map(ModelDomain.Field::getFieldName)
            .collect(Collectors.toList());
    }

    @Override
    public List<DataOwnerDomain> getDataOwnerByProjectId(Long projectId) {
        return Collections.emptyList();
//        return dataOwnerService.getAllByProjectId(projectId);
    }

    @Override
    public List<ThemeDomain> getThemeList(Long projectId) {
        return themeService.getThemesByProjectId(projectId);
    }

    /**
     * 发布指标
     *
     * @param projectId
     * @param id
     */
    @Override
    public void release(Long projectId, Long id) {
        this.indexService.update(
            new LambdaUpdateWrapper<IndexEntity>()
                .set(IndexEntity::getRelease, 1)
                .eq(IndexEntity::getStatus, 1)
                .eq(IndexEntity::getId, id));
    }

    /**
     * 发布指标
     *
     * @param projectId
     * @param id
     */
    @Override
    public void down(Long projectId, Long id) {
        this.indexService.update(
            new LambdaUpdateWrapper<IndexEntity>()
                .set(IndexEntity::getRelease, 0)
                .eq(IndexEntity::getRelease, 1)
                .eq(IndexEntity::getId, id));
    }
}
